/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.newworld.dmsapp2.ui.view;

import java.text.DateFormatSymbols;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Locale;
import java.util.TimeZone;

import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.DatePicker;
import android.widget.DatePicker.OnDateChangedListener;
import android.widget.NumberPicker;
import android.widget.NumberPicker.OnValueChangeListener;

import com.newworld.dmsapp2.R;

/**
 * A simple dialog containing an {@link android.widget.DatePicker}.
 * 
 * <p>
 * See the <a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a>
 * guide.
 * </p>
 */
public class TheDatePickerDialog extends AlertDialog implements
		OnClickListener, OnDateChangedListener {




	private static final int DEFAULT_START_YEAR = 1900;

	private static final int DEFAULT_END_YEAR = 2100;

	private NumberPicker mDaySpinner;

	private NumberPicker mMonthSpinner;

	private NumberPicker mYearSpinner;

	private Locale mCurrentLocale;

	private String[] mShortMonths;

	private int mNumberOfMonths;

	private Calendar mTempDate;

	private Calendar mMinDate;

	private Calendar mMaxDate;

	private Calendar mCurrentDate;
	private final OnDateSetListener mCallBack;

	/**
	 * The callback used to indicate the user is done filling in the date.
	 */
	public interface OnDateSetListener {

		/**
		 * @param calendar
		 *            选择的日期
		 * 
		 */
		void onDateSet(Calendar calendar);

	}

	@SuppressLint("NewApi")
	public TheDatePickerDialog(Context context,
			OnDateSetListener callBack, Calendar currentDate) {
		super(context);

		mCallBack = callBack;

		Context themeContext = getContext();
		setButton(BUTTON_POSITIVE, "确定", this);
		setButton(BUTTON_NEGATIVE, "取消", this);
		// setButton(BUTTON_POSITIVE,
		// themeContext.getText(android.R.string.date_time_done), this);
		setIcon(0);

		LayoutInflater inflater = (LayoutInflater) themeContext
				.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		View view = inflater.inflate(R.layout.date_picker_dialog,
				null);
		setView(view);
		setCurrentLocale(Locale.getDefault());
		OnValueChangeListener onChangeListener = new OnValueChangeListener() {
			public void onValueChange(NumberPicker picker, int oldVal,
					int newVal) {

				mDaySpinner.getChildAt(0).setFocusable(false);
				mYearSpinner.getChildAt(0).setFocusable(false);
				mMonthSpinner.getChildAt(0).setFocusable(false);
				
				mTempDate.setTimeInMillis(mCurrentDate.getTimeInMillis());
				// take care of wrapping of days and months to update greater
				// fields
				if (picker == mDaySpinner) {
					int maxDayOfMonth = mTempDate
							.getActualMaximum(Calendar.DAY_OF_MONTH);
					if (oldVal == maxDayOfMonth && newVal == 1) {
						mTempDate.add(Calendar.DAY_OF_MONTH, 1);
					} else if (oldVal == 1 && newVal == maxDayOfMonth) {
						mTempDate.add(Calendar.DAY_OF_MONTH, -1);
					} else {
						mTempDate.add(Calendar.DAY_OF_MONTH, newVal - oldVal);
					}
				} else if (picker == mMonthSpinner) {
					if (oldVal == 11 && newVal == 0) {
						mTempDate.add(Calendar.MONTH, 1);
					} else if (oldVal == 0 && newVal == 11) {
						mTempDate.add(Calendar.MONTH, -1);
					} else {
						mTempDate.add(Calendar.MONTH, newVal - oldVal);
					}
				} else if (picker == mYearSpinner) {
					mTempDate.set(Calendar.YEAR, newVal);
				} else {
					throw new IllegalArgumentException();
				}
				// now set the date to the adjusted one
				setDate(mTempDate.get(Calendar.YEAR),
						mTempDate.get(Calendar.MONTH),
						mTempDate.get(Calendar.DAY_OF_MONTH));
				updateSpinners();
			}
		};

		/*
		 * currentTimeInterval = timeInterval[currentPosition];
		 * show_button.setText(mCurrentDate.get(Calendar.YEAR) + "  " +
		 * (mCurrentDate.get(Calendar.MONTH) + 1) + "  " +
		 * mCurrentDate.get(Calendar.DAY_OF_MONTH) + "  " +
		 * currentTimeInterval);
		 */

		// day
		mDaySpinner = (NumberPicker) view.findViewById(R.id.select_day);
		mDaySpinner.setOnLongPressUpdateInterval(100);
		mDaySpinner.setOnValueChangedListener(onChangeListener);

		// month
		mMonthSpinner = (NumberPicker) view.findViewById(R.id.select_month);
		mMonthSpinner.setMinValue(0);
		mMonthSpinner.setMaxValue(mNumberOfMonths - 1);
		mMonthSpinner.setDisplayedValues(mShortMonths);
		mMonthSpinner.setOnLongPressUpdateInterval(200);
		mMonthSpinner.setOnValueChangedListener(onChangeListener);

		// year
		mYearSpinner = (NumberPicker) view.findViewById(R.id.select_year);
		mYearSpinner.setOnLongPressUpdateInterval(100);
		mYearSpinner.setOnValueChangedListener(onChangeListener);

		

		mDaySpinner.getChildAt(0).setFocusable(false);
		mYearSpinner.getChildAt(0).setFocusable(false);
		mMonthSpinner.getChildAt(0).setFocusable(false);
		

		mTempDate.clear();

		mTempDate.set(DEFAULT_START_YEAR, 0, 1);

		setMinDate(mTempDate.getTimeInMillis());

		// set the max date giving priority of the maxDate over endYear
		mTempDate.clear();

		mTempDate.set(DEFAULT_END_YEAR, 11, 31);

		setMaxDate(mTempDate.getTimeInMillis());

		// initialize to current date
		// mCurrentDate.setTimeInMillis(System.currentTimeMillis());
		mCurrentDate = currentDate;
		init(mCurrentDate.get(Calendar.YEAR), mCurrentDate.get(Calendar.MONTH),
				mCurrentDate.get(Calendar.DAY_OF_MONTH));
	}

	private void setDate(int year, int month, int dayOfMonth
			) {
		mCurrentDate.set(year, month, dayOfMonth);
		if (mCurrentDate.before(mMinDate)) {
			mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
		} else if (mCurrentDate.after(mMaxDate)) {
			mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
		}
		
	}

	/**
	 * Sets the minimal date supported by this {@link NumberPicker} in
	 * milliseconds since January 1, 1970 00:00:00 in
	 * {@link TimeZone#getDefault()} time zone.
	 * 
	 * @param minDate
	 *            The minimal supported date.
	 */
	public void setMinDate(long minDate) {
		mTempDate.setTimeInMillis(minDate);
		if (mTempDate.get(Calendar.YEAR) == mMinDate.get(Calendar.YEAR)
				&& mTempDate.get(Calendar.DAY_OF_YEAR) != mMinDate
						.get(Calendar.DAY_OF_YEAR)) {
			return;
		}
		mMinDate.setTimeInMillis(minDate);
		if (mCurrentDate.before(mMinDate)) {
			mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
		}
		updateSpinners();
	}

	/**
	 * Sets the maximal date supported by this {@link DatePicker} in
	 * milliseconds since January 1, 1970 00:00:00 in
	 * {@link TimeZone#getDefault()} time zone.
	 * 
	 * @param maxDate
	 *            The maximal supported date.
	 */
	public void setMaxDate(long maxDate) {
		mTempDate.setTimeInMillis(maxDate);
		if (mTempDate.get(Calendar.YEAR) == mMaxDate.get(Calendar.YEAR)
				&& mTempDate.get(Calendar.DAY_OF_YEAR) != mMaxDate
						.get(Calendar.DAY_OF_YEAR)) {
			return;
		}
		mMaxDate.setTimeInMillis(maxDate);
		if (mCurrentDate.after(mMaxDate)) {
			mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
		}
		updateSpinners();
	}

	@SuppressLint("NewApi")
	private void updateSpinners() {
		// set the spinner ranges respecting the min and max dates
		if (mCurrentDate.equals(mMinDate)) {
			mDaySpinner.setMinValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
			mDaySpinner.setMaxValue(mCurrentDate
					.getActualMaximum(Calendar.DAY_OF_MONTH));
			mDaySpinner.setWrapSelectorWheel(false);
			mMonthSpinner.setDisplayedValues(null);
			mMonthSpinner.setMinValue(mCurrentDate.get(Calendar.MONTH));
			mMonthSpinner.setMaxValue(mCurrentDate
					.getActualMaximum(Calendar.MONTH));
			mMonthSpinner.setWrapSelectorWheel(false);
		} else if (mCurrentDate.equals(mMaxDate)) {
			mDaySpinner.setMinValue(mCurrentDate
					.getActualMinimum(Calendar.DAY_OF_MONTH));
			mDaySpinner.setMaxValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
			mDaySpinner.setWrapSelectorWheel(false);
			mMonthSpinner.setDisplayedValues(null);
			mMonthSpinner.setMinValue(mCurrentDate
					.getActualMinimum(Calendar.MONTH));
			mMonthSpinner.setMaxValue(mCurrentDate.get(Calendar.MONTH));
			mMonthSpinner.setWrapSelectorWheel(false);
		} else {
			mDaySpinner.setMinValue(1);
			mDaySpinner.setMaxValue(mCurrentDate
					.getActualMaximum(Calendar.DAY_OF_MONTH));
			mDaySpinner.setWrapSelectorWheel(true);
			mMonthSpinner.setDisplayedValues(null);
			mMonthSpinner.setMinValue(0);
			mMonthSpinner.setMaxValue(11);
			mMonthSpinner.setWrapSelectorWheel(true);
		}

		// make sure the month names are a zero based array
		// with the months in the month spinner
		String[] displayedValues = Arrays.copyOfRange(mShortMonths,
				mMonthSpinner.getMinValue(), mMonthSpinner.getMaxValue() + 1);
		mMonthSpinner.setDisplayedValues(displayedValues);

		// year spinner range does not change based on the current date
		mYearSpinner.setMinValue(mMinDate.get(Calendar.YEAR));
		mYearSpinner.setMaxValue(mMaxDate.get(Calendar.YEAR));
		mYearSpinner.setWrapSelectorWheel(false);

		// set the spinner values
		mYearSpinner.setValue(mCurrentDate.get(Calendar.YEAR));
		mMonthSpinner.setValue(mCurrentDate.get(Calendar.MONTH));
		mDaySpinner.setValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));


	}

	/**
	 * Sets the current locale.
	 * 
	 * @param locale
	 *            The current locale.
	 */
	private void setCurrentLocale(Locale locale) {
		if (locale.equals(mCurrentLocale)) {
			return;
		}

		mCurrentLocale = locale;

		mTempDate = getCalendarForLocale(mTempDate, locale);
		mMinDate = getCalendarForLocale(mMinDate, locale);
		mMaxDate = getCalendarForLocale(mMaxDate, locale);
		mCurrentDate = getCalendarForLocale(mCurrentDate, locale);

		mNumberOfMonths = mTempDate.getActualMaximum(Calendar.MONTH) + 1;
		mShortMonths = new DateFormatSymbols().getShortMonths();

		if (usingNumericMonths()) {
			// We're in a locale where a date should either be all-numeric, or
			// all-text.
			// All-text would require custom NumberPicker formatters for day and
			// year.
			mShortMonths = new String[mNumberOfMonths];
			for (int i = 0; i < mNumberOfMonths; ++i) {
				mShortMonths[i] = String.format("%d", i + 1);
			}
		}
	}

	/**
	 * Gets a calendar for locale bootstrapped with the value of a given
	 * calendar.
	 * 
	 * @param oldCalendar
	 *            The old calendar.
	 * @param locale
	 *            The locale.
	 */
	private Calendar getCalendarForLocale(Calendar oldCalendar, Locale locale) {
		if (oldCalendar == null) {
			return Calendar.getInstance(locale);
		} else {
			final long currentTimeMillis = oldCalendar.getTimeInMillis();
			Calendar newCalendar = Calendar.getInstance(locale);
			newCalendar.setTimeInMillis(currentTimeMillis);
			return newCalendar;
		}
	}

	/**
	 * Tests whether the current locale is one where there are no real month
	 * names, such as Chinese, Japanese, or Korean locales.
	 */
	private boolean usingNumericMonths() {
		return Character.isDigit(mShortMonths[Calendar.JANUARY].charAt(0));
	}

	/**
	 * Initialize the state. If the provided values designate an inconsistent
	 * date the values are normalized before updating the spinners.
	 * 
	 * @param year
	 *            The initial year.
	 * @param monthOfYear
	 *            The initial month <strong>starting from zero</strong>.
	 * @param dayOfMonth
	 *            The initial day of the month.
	 * @param onDateChangedListener
	 *            How user is notified date is changed by user, can be null.
	 */
	public void init(int year, int monthOfYear, int dayOfMonth
			) {
		setDate(year, monthOfYear, dayOfMonth);

		updateSpinners();
	}

	@Override
	public void onDateChanged(DatePicker view, int year, int monthOfYear,
			int dayOfMonth) {
		// TODO Auto-generated method stub

	}

	private void tryNotifyDateSet() {
		if (mCallBack != null) {
			mCallBack.onDateSet(mCurrentDate);
		}
	}

	@Override
	public void onClick(DialogInterface dialog, int which) {
		// TODO Auto-generated method stub
		if (which == BUTTON_POSITIVE)
			tryNotifyDateSet();
	}
}
